﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;

namespace Serial
{
    public partial class Serial : Form
    {
        delegate void UpdateTextEventHandler(byte[] text);//委托，此为重点
        UpdateTextEventHandler updateText;

        private Encoding GB2312 = Encoding.GetEncoding("gb2312");

        private string Serial_Rx_Buff_Hex = "";    //缓存变量
        private string Serial_Rx_Buff_Ascii = "";    //缓存变量
        private long Comm_Received_Bytes = 0;                       //接收数据长度
        private long Comm_Send_Bytes = 0;                           //发送数据长度

        public Serial()
        {
            InitializeComponent();
            updateText = new UpdateTextEventHandler(UpdateTextBox);//实例化委托对象
            Serial_COM.Items.AddRange(SerialPort.GetPortNames());
        }

        //窗口关闭提示
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                DialogResult r = MessageBox.Show("您将关闭程序?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
                if (r != DialogResult.OK)
                {
                    e.Cancel = true;//不关闭窗口
                }
                else
                {
                    Serial1.Close();
                }
            }
        }

        //串口工作状态指示  如果开，则显示关闭串口，绿色，反之显示打开串口，红色
        private void Serial_Status()
        {
            //设置按钮状态
            Serial_OpenPort.Text = Serial1.IsOpen ? "关闭串口" : "打开串口";
            Serial_Open_flag.ForeColor = Serial1.IsOpen ? Color.Green : Color.Red;
        }

        private void Serial_Open()
        {
            if (Serial1.IsOpen)
            {
                Serial1.Close();
            }
            Serial1 = new SerialPort(Serial_COM.Text);
            Serial1.BaudRate = int.Parse(Serial_Rate.Text);
            Serial1.DataBits = int.Parse(Serial_DataBit.Text);
            Serial1.Encoding = GB2312;
            //Serial1.ReadTimeout = 400;
            //Serial1.WriteTimeout = 400;
            switch (Serial_Flow.SelectedIndex)
            {
                case 0: Serial1.Handshake = Handshake.None; break;
                case 1: Serial1.Handshake = Handshake.XOnXOff; break;
                case 2: Serial1.Handshake = Handshake.RequestToSend; break;
                case 3: Serial1.Handshake = Handshake.RequestToSendXOnXOff; break;
                default: Serial1.Handshake = Handshake.None; break;
            }
            switch (Serial_Parity.SelectedIndex)
            {
                case 0:Serial1.Parity = Parity.None; break;
                case 1:Serial1.Parity = Parity.Even; break;
                case 2:Serial1.Parity = Parity.Odd; break;
                case 3: Serial1.Parity = Parity.Space; break;
                default:Serial1.Parity = Parity.None; break;
            }
            switch (Serial_StopBit.SelectedIndex)
            {
                case 0: Serial1.StopBits = StopBits.One; break;
                case 1: Serial1.StopBits = StopBits.OnePointFive; break;
                case 2: Serial1.StopBits = StopBits.Two; break;
                default: Serial1.StopBits = StopBits.One; break;
            }
            try
            {
                Serial1.Open();

                Serial1.DataReceived += new SerialDataReceivedEventHandler(Com_DataReceived);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Serial_Param_Changed(object sender, EventArgs e)
        {
            Serial_Open();
            Serial_Status();
        }

        private void Button_OpenPort_Click(object sender, EventArgs e)
        {
            if (Serial1.IsOpen)
            {
                Serial1.Close();
            }
            else
            {
                Serial_Open();
            }
            Serial_Status();
        }

        private void Com_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            if (Serial1.IsOpen)
            {
                try
                {
                    //string ReDatas = Serial1.ReadExisting();
                    //Comm_Received_Bytes += ReDatas.Length;
                    //开辟接收缓冲区
                    byte[] ReDatas = new byte[Serial1.BytesToRead];
                    //从串口读取数据
                    //Serial1.Read(ReDatas, 0, ReDatas.Length);
                    
                    Comm_Received_Bytes += Serial1.Read(ReDatas, 0, Serial1.BytesToRead);
                    //实现数据的解码与显示
                    this.Invoke(updateText, ReDatas);
                    //this.Invoke(updateText, ReDatas);
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void Serial_Load(object sender, EventArgs e)
        {
        }

        private byte[] Str2Hex(string Str)
        {
            int i = 0;
            string HexStr = Str.Replace(" ", "");
            int len = HexStr.Length;
            byte[] Return_Arr = new byte[len/2];
            string TempStr;

            while(len > 1)
            {
                len -= 2;
                TempStr = HexStr.Substring(i*2, 2);
                Return_Arr[i++] = Convert.ToByte(TempStr, 16);
            }
            return Return_Arr;
        }

        private string Hex2Str(byte[] tempChar)
        {
            int i = 0;
            int len = tempChar.Length;
            string Return_Arr = "";

            while (len > 0)
            {
                len -= 1;
                Return_Arr += tempChar[i++].ToString("X2") + " ";
            }
            return Return_Arr+"\n";
        }

        private void Serial_Send_Data_Click(object sender, EventArgs e)
        {
            if (Serial_SendText.Text.Length > 0)
            {
                string TxBuff = Serial_SendText.Text;
                if (Serial1.IsOpen == false)
                {
                    Serial_Open();
                    Serial_Status();
                }

                if (Serial_SendWithHex.Checked == false)
                {
                    byte[] Tx = GB2312.GetBytes(TxBuff);
                    Comm_Send_Bytes += Tx.Length;
                    Serial_SendNum.Text = "发送:" + Comm_Send_Bytes.ToString();
                    Serial1.Write(Tx, 0, Tx.Length);
                }
                else
                {
                    byte[] Serial_SendBuff = Str2Hex(TxBuff);
                    Comm_Send_Bytes += Serial_SendBuff.Length;
                    Serial_SendNum.Text = "发送:" + Comm_Send_Bytes.ToString();
                    Serial1.Write(Serial_SendBuff, 0, Serial_SendBuff.Length);
                }
            }
            else
            {
                MessageBox.Show("发送框不能为空！");
            }
        }

        //显示方式确认
        private void Serial_Display_Hex_CheckedChanged(object sender, EventArgs e)
        {
            if (Serial_Display_Hex.Checked == true)
            {
                DialogResult r = MessageBox.Show("您确定已hex显示?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
                if (r == DialogResult.OK)
                {
                    Serial_Display_Hex.Checked = true;
                    
                    Serial_RecvText.Text = Serial_Rx_Buff_Hex;
                }
                else
                {
                    Serial_Display_Hex.Checked = false;
                }
            }
            else
            {
                DialogResult r = MessageBox.Show("您确定已文本显示?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
                if (r == DialogResult.OK)
                {
                    Serial_Display_Hex.Checked = false;

                    Serial_RecvText.Text = Serial_Rx_Buff_Ascii;
                }
                else
                {
                    Serial_Display_Hex.Checked = true;
                }
            }
        }

        //委托处理事件
        private void UpdateTextBox(byte[] text)
        {
            if (Serial_Display_Hex.Checked == false)
            {
                string str = GB2312.GetString(text);
                Serial_RecvText.Text += str + "\r\n";
                Serial_Rx_Buff_Ascii += str;
                Serial_Rx_Buff_Hex += Hex2Str(text);
            }
            else
            {
                string str = GB2312.GetString(text);
                Serial_RecvText.Text += Hex2Str(text) + "\r\n";
                Serial_Rx_Buff_Hex += Hex2Str(text);
                Serial_Rx_Buff_Ascii += str;
            }

            Serial_RecvNum.Text = "接收:" + Comm_Received_Bytes.ToString();
        }

        //清空输入输出TextBox 发送接收数据长度及label
        private void Serial_Empty_Click(object sender, EventArgs e)
        {
            Comm_Received_Bytes = 0;
            Comm_Send_Bytes = 0;
            Serial_SendNum.Text = "发送:0";
            Serial_RecvNum.Text = "接收:0";

            Serial_RecvText.Text = "";
            Serial_SendText.Text = "";
            Serial_Rx_Buff_Hex = "";
            Serial_Rx_Buff_Ascii = "";
        }

        //TextBox 框自动跳到最后一行
        private void Serial_RecvText_TextChanged(object sender, EventArgs e)
        {
            Serial_RecvText.SelectionStart = Serial_RecvText.Text.Length;
            Serial_RecvText.ScrollToCaret();
        }

        private void Serial_SendText_PressKey(object sender, KeyPressEventArgs e)
        {
            char KeyChar = Convert.ToChar(e.KeyChar);
            //当输入为0-9的数字、小数点、回车和退格键时不阻止
            if(Serial_SendWithHex.Checked == true)
            {
                if (char.IsNumber(KeyChar) || (KeyChar >= 'a' && KeyChar <= 'f') || (KeyChar >= 'A' && KeyChar <= 'F') || KeyChar == 13 || KeyChar == (char)8 || KeyChar == ' ')
                {
                    e.Handled = false;
                }
                else
                {
                    //阻止从键盘输入键
                    e.Handled = true;
                    MessageBox.Show("不是有效的Hex 字符组合{'0-9','a-f','A-F',''}\r\n 每两个字符之间一个空格。");
                }
            }
        }
    }
}
